//---------------------------------------------------------------------------

#include "vcl_stl.h"
#pragma hdrstop

#include "h_base.h"
#include "h_xml.h"
#include "h_global.h"
using namespace h_base;
using namespace h_xml;

#include "t_mainform.h"
#include "h_g.h"
#include "h_stageicon.h"
#include "h_stage.h"
#include "t_normaljobform.h"
#include "t_connectorform.h"
#include "t_externjobform.h"
#include "t_eventfireform.h"
#include "t_eventwaitform.h"
#include "t_groupform.h"
#include "t_timeform.h"
#include "t_batchjobform.h"
#include "h_i18n.h"
//---------------------------------------------------------------------------

// class HStage

__fastcall HStage::HStage(void)
{
   FIcon = NULL;
   FLabel = NULL;
}

__fastcall HStage::~HStage(void)
{
   if( FIcon != NULL )
      delete FIcon;
   if( FLabel != NULL )
      delete FLabel;
}

UTF8String __fastcall HStage::GetGroupId(void)
{
   return FGroupId;
}

void __fastcall HStage::SetGroupId(const UTF8String &GroupId)
{
   FGroupId = GroupId;
}

UTF8String __fastcall HStage::GetName(void)
{
   return FName;
}

void __fastcall HStage::SetName(const UTF8String &Name)
{
   FName = Name;
}

HStageIcon * __fastcall HStage::GetIcon(void)
{
   return FIcon;
}

void __fastcall HStage::CreateIcon(TWinControl *Parent)
{
   int Width, Height;

   if( FIcon != NULL )
      return;

   FIcon = new HStageIcon(Parent);
   FIcon->SetType(GetIconType());
   FIcon->SetEnlarge(GetIconEnlarge());
   FIcon->SetCaption(GetCaption());
   FIcon->SetPartFlag(GetPartFlag());
   FIcon->SetExternFlag(GetExternFlag());
   FIcon->SetLoopFlag(GetLoopFlag());
   GetIconSize(Width, Height);
   FIcon->Width = Width;
   FIcon->Height = Height;
   FIcon->Parent = Parent;
   FIcon->ShowHint = true;
   FIcon->Hint = GetHint();
}

void __fastcall HStage::Move(int x, int y)
{
   if( FIcon == NULL )
      return;

   FIcon->Left = x;
   FIcon->Top = y;
   AdjustLabel();
}

void __fastcall HStage::AdjustLabel()
{
   if ( FLabel == NULL )
   {
      return;
   }

   FLabel->Top = FIcon->Top + FIcon->Height + 4;
   FLabel->Left = FIcon->Left + FIcon->Width / 2 - FLabel->Width / 2;
}

void __fastcall HStage::RefreshCaption(void)
{
   int Width, Height;

   GetIconSize(Width, Height);
   FIcon->Width = Width;
   FIcon->Height = Height;
   FIcon->SetEnlarge(GetIconEnlarge());
   FIcon->SetCaption(GetCaption());
   FIcon->SetPartFlag(GetPartFlag());
   FIcon->SetExternFlag(GetExternFlag());
   FIcon->SetLoopFlag(GetLoopFlag());
   FIcon->Hint = GetHint();

   if ( FLabel != NULL )
   {
      FLabel->Caption = GetCaption();
      AdjustLabel();
   }
}

bool __fastcall HStage::IsValidJobName(const string &Name)
{
   const char *s;

   if ( Name[0] != '_' && !isalpha(Name[0]) &&
        !( Name[0] & 0x80 ) )
   {
      return false;
   }

   for ( s = Name.c_str(); *s != '\0'; s++ )
   {
      if ( *s & 0x80 )
      {
         if ( (unsigned char)(*(s + 1)) >= 0x40 )
         {
            s++;
            continue;
         }
         return false;
      }
      if ( *s != '_' && !isalnum(*s) )
      {
         return false;
      }
   }

   return true;
}

int HStage::StringToAlarmTimeType(const UTF8String &Str)
{
   if ( Str == "At the moment" || Str == "1" )
   {
      return 1;
   }

   if ( Str == "Duration from the batch starting" || Str == "2" )
   {
      return 2;
   }

   if ( Str == "Duration from the job starting" || Str == "3" )
   {
      return 3;
   }

   return 0;
}

UTF8String HStage::AlarmTimeTypeToString(int Type)
{
   if ( Type == 1 )
   {
      return "1";
   }

   if ( Type == 2 )
   {
      return "2";
   }

   if ( Type == 3 )
   {
      return "3";
   }

   return "";
}

// class HStageJob

__fastcall HStageJob::HStageJob(void)
   : HStage(), FInfo()
{
}

HStage * __fastcall HStageJob::Clone(void)
{
   return new HStageJob;
}

UTF8String __fastcall HStageJob::GetType(void)
{
   return "JOB";
}

int __fastcall HStageJob::GetIconEnlarge(void)
{
   return FInfo.Enlarge;
}

bool __fastcall HStageJob::EditProperty(void)
{
   return NormalJobForm->Edit(this);
}

void __fastcall HStageJob::SaveProperty(HXmlTree *Node)
{
   char TmpStr[80 + 1];

   Node->SetProperty("COMMAND", FInfo.Command.c_str());
   Node->SetProperty("RESTORE_COMMAND", FInfo.RestoreCommand.c_str());
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   Node->SetProperty("SPECIAL_DATE", FInfo.SpecialDate.c_str());
   Node->SetProperty("BUSINESS_TYPE", FInfo.BusinessType.c_str());
   Node->SetProperty("COND_NOT", FInfo.CondNot ? "Y" : "");
   Node->SetProperty("CONDITION_FILE", FInfo.ConditionFile.c_str());
   Node->SetProperty("ADDITIONAL_LOG", FInfo.AdditionalLog.c_str());
   Node->SetProperty("ALARM_TIME_TYPE", AlarmTimeTypeToString(FInfo.AlarmTimeType).c_str());
   Node->SetProperty("ALARM_TIME", FInfo.AlarmTime.c_str());
   Node->SetProperty("JOB_TRIGGER", FInfo.JobTrigger.c_str());
   Node->SetProperty("PARTITION_FILE", FInfo.PartitionFile.c_str());
   Node->SetProperty("EXCLUSIVE", FInfo.Exclusive ? "Y" : "");
   snprintf(TmpStr, 80, "%d", FInfo.ParallelJobNumber);
   Node->SetProperty("PARALLEL_JOB_NUMBER", TmpStr, "0");
   snprintf(TmpStr, 80, "%d", FInfo.Priority);
   Node->SetProperty("PRIORITY", TmpStr, "0");
   Node->SetProperty("AUTO_RERUN", FInfo.AutoRerun.c_str());
   snprintf(TmpStr, 80, "%d", FInfo.Enlarge);
   Node->SetProperty("ENLARGE", TmpStr, "0");
   Node->SetProperty("ANCHOR", FInfo.Anchor ? "Y" : "");
   Node->SetProperty("TAG", FInfo.Tag.c_str());
   Node->SetProperty("RUNNING_GROUP", FInfo.RunningGroup.c_str());
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   Node->SetValues("RESOURCE_LIST", FInfo.ResourceList);
   Node->SetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
   Node->SetProperty("LOOP_START_TIME", FInfo.LoopStartTime.c_str());
   Node->SetProperty("LOOP_END_TIME", FInfo.LoopEndTime.c_str());
   Node->SetProperty("LOOP_INTERVAL", FInfo.LoopInterval.c_str());
   Node->SetProperty("LOOP_COUNT", FInfo.LoopCount.c_str());
   Node->SetProperty("LOOP_CONDITION_VARIABLE", FInfo.LoopConditionVariable.c_str());
}

void __fastcall HStageJob::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   if ( XmlPropertyFlag )
   {
      FInfo.Command = Node->GetProperty("COMMAND").c_str();
      FInfo.RestoreCommand = Node->GetProperty("RESTORE_COMMAND").c_str();
      FInfo.SpecialDate = Node->GetProperty("SPECIAL_DATE").c_str();
      FInfo.BusinessType = Node->GetProperty("BUSINESS_TYPE").c_str();
      FInfo.CondNot = Node->GetProperty("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetProperty("CONDITION_FILE").c_str();
      FInfo.AdditionalLog = Node->GetProperty("ADDITIONAL_LOG").c_str();
      FInfo.AlarmTimeType = StringToAlarmTimeType(Node->GetProperty("ALARM_TIME_TYPE").c_str());
      FInfo.AlarmTime = Node->GetProperty("ALARM_TIME").c_str();
      FInfo.JobTrigger = Node->GetProperty("JOB_TRIGGER").c_str();
      FInfo.PartitionFile = Node->GetProperty("PARTITION_FILE").c_str();
      FInfo.Exclusive = Node->GetProperty("EXCLUSIVE") == "Y";
      FInfo.ParallelJobNumber = StrToInt(Node->GetProperty("PARALLEL_JOB_NUMBER").c_str());
      FInfo.Priority = StrToInt(Node->GetProperty("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetProperty("AUTO_RERUN").c_str();
      FInfo.Enlarge = StrToInt(Node->GetProperty("ENLARGE").c_str());
      FInfo.Anchor = Node->GetProperty("ANCHOR") == "Y";
      FInfo.Tag = Node->GetProperty("TAG").c_str();
      FInfo.RunningGroup = Node->GetProperty("RUNNING_GROUP").c_str();
      FInfo.LoopStartTime = Node->GetProperty("LOOP_START_TIME").c_str();
      FInfo.LoopEndTime = Node->GetProperty("LOOP_END_TIME").c_str();
      FInfo.LoopInterval = Node->GetProperty("LOOP_INTERVAL").c_str();
      FInfo.LoopCount = Node->GetProperty("LOOP_COUNT").c_str();
      FInfo.LoopConditionVariable = Node->GetProperty("LOOP_CONDITION_VARIABLE").c_str();
   }
   else
   {
      FInfo.Command = Node->GetValue("COMMAND").c_str();
      FInfo.RestoreCommand = Node->GetValue("RESTORE_COMMAND").c_str();
      FInfo.SpecialDate = Node->GetValue("SPECIAL_DATE").c_str();
      FInfo.BusinessType = Node->GetValue("BUSINESS_TYPE").c_str();
      FInfo.CondNot = Node->GetValue("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetValue("CONDITION_FILE").c_str();
      FInfo.AdditionalLog = Node->GetValue("ADDITIONAL_LOG").c_str();
      FInfo.AlarmTimeType = StringToAlarmTimeType(Node->GetValue("ALARM_TIME_TYPE").c_str());
      FInfo.AlarmTime = Node->GetValue("ALARM_TIME").c_str();
      FInfo.JobTrigger = Node->GetValue("JOB_TRIGGER").c_str();
      FInfo.PartitionFile = Node->GetValue("PARTITION_FILE").c_str();
      FInfo.Exclusive = Node->GetValue("EXCLUSIVE") == "Y";
      FInfo.ParallelJobNumber = StrToInt(Node->GetValue("PARALLEL_JOB_NUMBER").c_str());
      FInfo.Priority = StrToInt(Node->GetValue("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetValue("AUTO_RERUN").c_str();
      FInfo.Enlarge = StrToInt(Node->GetValue("ENLARGE").c_str());
      FInfo.Anchor = Node->GetValue("ANCHOR") == "Y";
      FInfo.Tag = Node->GetValue("TAG").c_str();
      FInfo.RunningGroup = Node->GetValue("RUNNING_GROUP").c_str();
      FInfo.LoopStartTime = Node->GetValue("LOOP_START_TIME").c_str();
      FInfo.LoopEndTime = Node->GetValue("LOOP_END_TIME").c_str();
      FInfo.LoopInterval = Node->GetValue("LOOP_INTERVAL").c_str();
      FInfo.LoopCount = Node->GetValue("LOOP_COUNT").c_str();
      FInfo.LoopConditionVariable = Node->GetValue("LOOP_CONDITION_VARIABLE").c_str();
   }

   if ( FInfo.AutoRerun == "0" )
   {
      FInfo.AutoRerun = "";
   }

   FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
   Node->GetValues("RESOURCE_LIST", FInfo.ResourceList);
   Node->GetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

UTF8String __fastcall HStageJob::GetCaption(void)
{
   return GetName();
}

bool __fastcall HStageJob::GetPartFlag(void)
{
   return FInfo.PartitionFile != "";
}

bool __fastcall HStageJob::GetExternFlag(void)
{
   return !FInfo.ExternJobList.empty();
}

bool __fastcall HStageJob::GetLoopFlag(void)
{
   return FInfo.LoopInterval != "";
}

int __fastcall HStageJob::GetIconType(void)
{
   return 0;
}

void __fastcall HStageJob::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapJobBg1[0]->Width * ( FInfo.Enlarge + 3 );
   Height = h_g::BitmapJobBg1[0]->Height;
}

UTF8String __fastcall HStageJob::GetHint()
{
   char TmpStr[8192 + 1];
   snprintf(TmpStr, 8192, h_g::I18nString("h_stage:JOB_HINT"),
      GetName().c_str(), FInfo.Command.c_str(), FInfo.Tag.c_str());
   UTF8String Hint = TmpStr;

   if( FInfo.Description != "" )
   {
      vector<string> Text;
      h_base::SplitString(FInfo.Description.c_str(), '\n', Text);
      for( int i = 0; i < Text.size(); i++ )
      {
         if( i == 0 )
            Hint += UTF8String(h_g::I18nString("h_stage:DESCRIPTION")) + Text[i].c_str();
         else
            Hint += UTF8String("\n              ") + Text[i].c_str();
      }
   }

   return Hint;
}

void __fastcall HStageJob::GetJobListInfo(const UTF8String &GroupId,
   HJobListInfo &JobListInfo)
{
   JobListInfo = HJobListInfo();
   JobListInfo.Name = GroupId + h_g::JobNameDelimiter + GetName();
   JobListInfo.Command = FInfo.Command;
   JobListInfo.CommandUpper = JobListInfo.Command.UpperCase();
   JobListInfo.TagUpper = FInfo.Tag.UpperCase();
}

void __fastcall HStageJob::GetInfo(HInfo &Info)
{
   FInfo.Name = GetName();
   Info = FInfo;
}

static bool IsValidVarName(const string &VarName)
{
   for( int i = 0; i < VarName.length(); i++ )
   {
      if( !isalnum(VarName[i]) && VarName[i] != '_' )
         return false;
   }

   if( VarName.length() == 0 || isdigit(VarName[0]) )
      return false;

   return true;
}

static bool VarTypeIsNumeric(const string &VarName)
{
   return false;
}

static string GetVar(const string &VarName)
{
   return "";
}

bool __fastcall HStageJob::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   if( Info.Name != FInfo.Name )
   {
      if( MainForm->ControlExist(Info.Name) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:DUPLICATED_NAME")) +
            Info.Name + ")";
         return false;
      }
      if( !IsValidJobName(Info.Name.c_str()) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_NAME")) +
            Info.Name + ")";
         return false;
      }
   }

   if ( Info.AlarmTime != "" )
   {
      if ( Info.AlarmTime.Length() != 5 || Info.AlarmTime[3] != ':' )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_TIME")) +
            Info.AlarmTime + ")";
         return false;
      }
   }

   if ( Info.LoopInterval != "" )
   {
      if ( Info.LoopStartTime != "" )
      {
         if ( Info.LoopStartTime.Length() != 5 || Info.LoopStartTime[3] != ':' )
         {
            ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_TIME")) +
               Info.LoopStartTime + ")";
            return false;
         }
      }
      if ( Info.LoopEndTime != "" )
      {
         if ( Info.LoopEndTime.Length() != 5 || Info.LoopEndTime[3] != ':' )
         {
            ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_TIME")) +
               Info.LoopEndTime + ")";
            return false;
         }
      }
      int Interval = StrToInt(Info.LoopInterval.c_str());
      if ( Interval < 30 || Interval > 18000 )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_TIME")) +
            "(30, 18000) " + Info.LoopInterval + ")";
         return false;
      }
   }

   FInfo = Info;
   SetName(Info.Name);
   RefreshCaption();
   return true;
}

// class HStageConnector

HStage * __fastcall HStageConnector::Clone(void)
{
   return new HStageConnector;
}

UTF8String __fastcall HStageConnector::GetType(void)
{
   return "CONNECTOR";
}

int __fastcall HStageConnector::GetIconEnlarge(void)
{
   return 0;
}

bool __fastcall HStageConnector::EditProperty(void)
{
   return ConnectorForm->Edit(this);
}

void __fastcall HStageConnector::SaveProperty(HXmlTree *Node)
{
   Node->SetProperty("HIDE_ARROW", FInfo.HideArrow ? "Y" : "");
}

void __fastcall HStageConnector::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   HString Value;

   if ( XmlPropertyFlag )
   {
      Value = Node->GetProperty("HIDE_ARROW");
   }
   else
   {
      Value = Node->GetValue("HIDE_ARROW");
   }

   FInfo.HideArrow = Value == "Y" || Value == "true";
}

UTF8String __fastcall HStageConnector::GetCaption(void)
{
   return "";
}

bool __fastcall HStageConnector::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageConnector::GetExternFlag(void)
{
   return false;
}

bool __fastcall HStageConnector::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageConnector::GetIconType(void)
{
   return 1;
}

void __fastcall HStageConnector::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapConnector[0]->Width;
   Height = h_g::BitmapConnector[0]->Height;
}

UTF8String __fastcall HStageConnector::GetHint()
{
   char TmpStr[8192 + 1];
   snprintf(TmpStr, 8192, h_g::I18nString("h_stage:CONNECTOR_HINT"),
      FInfo.HideArrow ? "true" : "false");
   return UTF8String(TmpStr);
}

void __fastcall HStageConnector::GetInfo(HInfo &Info)
{
   Info = FInfo;
}

bool __fastcall HStageConnector::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   FInfo = Info;
   RefreshCaption();
   return true;
}

// class HStageExternJob

HStage * __fastcall HStageExternJob::Clone(void)
{
   return new HStageExternJob;
}

UTF8String __fastcall HStageExternJob::GetType(void)
{
   return "EXTERN_JOB";
}

int __fastcall HStageExternJob::GetIconEnlarge(void)
{
   return FInfo.Enlarge;
}

bool __fastcall HStageExternJob::EditProperty(void)
{
   return ExternJobForm->Edit(this);
}

void __fastcall HStageExternJob::SaveProperty(HXmlTree *Node)
{
   char TmpStr[80 + 1];

   Node->SetProperty("EXTERN_GROUP", FInfo.ExternGroup.c_str());
   Node->SetProperty("EXTERN_JOB", FInfo.ExternJob.c_str());
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   snprintf(TmpStr, 200, "%d", FInfo.Enlarge);
   Node->SetProperty("ENLARGE", TmpStr, "0");
}

void __fastcall HStageExternJob::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   if ( XmlPropertyFlag )
   {
      FInfo.ExternGroup = Node->GetPropertyUpper("EXTERN_GROUP").c_str();
      FInfo.ExternJob = Node->GetPropertyUpper("EXTERN_JOB").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.Enlarge = StrToInt(Node->GetProperty("ENLARGE").c_str());
   }
   else
   {
      FInfo.ExternGroup = Node->GetValueUpper("EXTERN_GROUP").c_str();
      FInfo.ExternJob = Node->GetValueUpper("EXTERN_JOB").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.Enlarge = StrToInt(Node->GetValue("ENLARGE").c_str());
   }
}

UTF8String __fastcall HStageExternJob::GetCaption(void)
{
   return FInfo.ExternGroup + "." + FInfo.ExternJob;
}

bool __fastcall HStageExternJob::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageExternJob::GetExternFlag(void)
{
   return false;
}

bool __fastcall HStageExternJob::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageExternJob::GetIconType(void)
{
   return 2;
}

void __fastcall HStageExternJob::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapExternJobBg1[0]->Width * ( FInfo.Enlarge + 3 );
   Height = h_g::BitmapExternJobBg1[0]->Height;
}

UTF8String __fastcall HStageExternJob::GetHint()
{
   char TmpStr[8192 + 1];
   snprintf(TmpStr, 8192, h_g::I18nString("h_stage:EXTERN_JOB_HINT"),
      FInfo.ExternGroup.c_str(), FInfo.ExternJob.c_str());

   UTF8String Hint = TmpStr;

   if( FInfo.Description != "" )
   {
      vector<string> Text;
      h_base::SplitString(FInfo.Description.c_str(), '\n', Text);
      for( int i = 0; i < Text.size(); i++ )
      {
         if( i == 0 )
            Hint += UTF8String(h_g::I18nString("h_stage:DESCRIPTION")) +
               Text[i].c_str();
         else
            Hint += UTF8String("\n              ") + Text[i].c_str();
      }
   }

   return Hint;
}

void __fastcall HStageExternJob::GetInfo(HInfo &Info)
{
   Info = FInfo;
}

bool __fastcall HStageExternJob::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   FInfo = Info;
   RefreshCaption();
   return true;
}

// class HStageEventFire

HStage * __fastcall HStageEventFire::Clone(void)
{
   return new HStageEventFire;
}

UTF8String __fastcall HStageEventFire::GetType(void)
{
   return "EVENT_FIRE";
}

int __fastcall HStageEventFire::GetIconEnlarge(void)
{
   return 0;
}

bool __fastcall HStageEventFire::EditProperty(void)
{
   return EventFireForm->Edit(this);
}

void __fastcall HStageEventFire::SaveProperty(HXmlTree *Node)
{
   char TmpStr[80 + 1];

   Node->SetProperty("HOST_NAME", FInfo.HostName.c_str());
   Node->SetProperty("EVENT", FInfo.Event.c_str());
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   Node->SetProperty("SPECIAL_DATE", FInfo.SpecialDate.c_str());
   Node->SetProperty("COND_NOT", FInfo.CondNot ? "Y" : "");
   Node->SetProperty("CONDITION_FILE", FInfo.ConditionFile.c_str());
   Node->SetProperty("JOB_TRIGGER", FInfo.JobTrigger.c_str());
   snprintf(TmpStr, 200, "%d", FInfo.Priority);
   Node->SetProperty("PRIORITY", TmpStr, "0");
   Node->SetProperty("AUTO_RERUN", FInfo.AutoRerun.c_str());
   Node->SetProperty("TAG", FInfo.Tag.c_str());
   Node->SetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

void __fastcall HStageEventFire::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   if ( XmlPropertyFlag )
   {
      FInfo.HostName = Node->GetProperty("HOST_NAME").c_str();
      FInfo.Event = Node->GetPropertyUpper("EVENT").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetProperty("SPECIAL_DATE").c_str();
      FInfo.CondNot = Node->GetProperty("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetProperty("CONDITION_FILE").c_str();
      FInfo.JobTrigger = Node->GetProperty("JOB_TRIGGER").c_str();
      FInfo.Priority = StrToInt(Node->GetProperty("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetProperty("AUTO_RERUN").c_str();
      FInfo.Tag = Node->GetProperty("TAG").c_str();
   }
   else
   {
      FInfo.HostName = Node->GetValue("HOST_NAME").c_str();
      FInfo.Event = Node->GetValueUpper("EVENT").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetValue("SPECIAL_DATE").c_str();
      FInfo.CondNot = Node->GetValue("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetValue("CONDITION_FILE").c_str();
      FInfo.JobTrigger = Node->GetValue("JOB_TRIGGER").c_str();
      FInfo.Priority = StrToInt(Node->GetValue("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetValue("AUTO_RERUN").c_str();
      FInfo.Tag = Node->GetValue("TAG").c_str();
   }

   if ( FInfo.AutoRerun == "0" )
   {
      FInfo.AutoRerun = "";
   }

   Node->GetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

UTF8String __fastcall HStageEventFire::GetCaption(void)
{
   return "";
}

bool __fastcall HStageEventFire::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageEventFire::GetExternFlag(void)
{
   return !FInfo.ExternJobList.empty();
}

bool __fastcall HStageEventFire::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageEventFire::GetIconType(void)
{
   return 3;
}

void __fastcall HStageEventFire::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapFwBg[0]->Width;
   Height = h_g::BitmapFwBg[0]->Height;
}

UTF8String __fastcall HStageEventFire::GetHint()
{
   char TmpStr[8192 + 1];
   snprintf(TmpStr, 8192, h_g::I18nString("h_stage:EVENT_FIRE_HINT"),
      FInfo.HostName.c_str(), FInfo.Event.c_str());

   UTF8String Hint = TmpStr;

   if( FInfo.Description != "" )
   {
      vector<string> Text;
      h_base::SplitString(FInfo.Description.c_str(), '\n', Text);
      for( int i = 0; i < Text.size(); i++ )
      {
         if( i == 0 )
            Hint += UTF8String(h_g::I18nString("h_stage:DESCRIPTION")) +
               Text[i].c_str();
         else
            Hint += UTF8String("\n              ") + Text[i].c_str();
      }
   }

   return Hint;
}

void __fastcall HStageEventFire::GetJobListInfo(const UTF8String &GroupId,
   HJobListInfo &JobListInfo)
{
   JobListInfo = HJobListInfo();
   JobListInfo.Name = GroupId + h_g::JobNameDelimiter + GetName();
   JobListInfo.Command = UTF8String("simbat_evnt fire \"") +
      FInfo.HostName + "\" \"" +
      FInfo.Event + "\"";
   JobListInfo.CommandUpper = JobListInfo.Command.UpperCase();
   JobListInfo.TagUpper = FInfo.Tag.UpperCase();
}

void __fastcall HStageEventFire::GetInfo(HInfo &Info)
{
   FInfo.Name = GetName();
   Info = FInfo;
}

bool __fastcall HStageEventFire::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   if( Info.Name != FInfo.Name )
   {
      if( MainForm->ControlExist(Info.Name) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:DUPLICATED_NAME")) +
            Info.Name + ")";
         return false;
      }
      if( !IsValidJobName(Info.Name.c_str()) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_NAME")) +
            Info.Name + ")";
         return false;
      }
   }

   if( Info.HostName == "" )
   {
      ErrorString = h_g::I18nString("h_stage:HOST_NAME_MUST_NOT_BE_EMPTY");
      return false;
   }

   if( Info.Event == "" )
   {
      ErrorString = h_g::I18nString("h_stage:EVENT_MUST_NOT_BE_EMPTY");
      return false;
   }

   FInfo = Info;
   SetName(Info.Name);
   RefreshCaption();
   return true;
}

// class HStageEventWait

HStage * __fastcall HStageEventWait::Clone(void)
{
   return new HStageEventWait;
}

UTF8String __fastcall HStageEventWait::GetType(void)
{
   return "EVENT_WAIT";
}

int __fastcall HStageEventWait::GetIconEnlarge(void)
{
   return 0;
}

bool __fastcall HStageEventWait::EditProperty(void)
{
   return EventWaitForm->Edit(this);
}

void __fastcall HStageEventWait::SaveProperty(HXmlTree *Node)
{
   char TmpStr[80 + 1];

   Node->SetProperty("EVENT", FInfo.Event.c_str());
   Node->SetProperty("WAIT_FOR_FILE", FInfo.WaitForFile.c_str());
   Node->SetProperty("WAIT_FOR_TIME", FInfo.WaitForTime.c_str());
   Node->SetProperty("WAIT_FOR_COMMAND", FInfo.WaitForCommand.c_str());
   Node->SetProperty("WAIT_FOR_OPERATOR", FInfo.WaitForOperator ? "Y" : "");
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   Node->SetProperty("SPECIAL_DATE", FInfo.SpecialDate.c_str());
   Node->SetProperty("COND_NOT", FInfo.CondNot ? "Y" : "");
   Node->SetProperty("CONDITION_FILE", FInfo.ConditionFile.c_str());
   Node->SetProperty("JOB_TRIGGER", FInfo.JobTrigger.c_str());
   snprintf(TmpStr, 80, "%d", FInfo.Priority);
   Node->SetProperty("PRIORITY", TmpStr, "0");
   Node->SetProperty("AUTO_RERUN", FInfo.AutoRerun.c_str());
   Node->SetProperty("TAG", FInfo.Tag.c_str());
   Node->SetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

void __fastcall HStageEventWait::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   if ( XmlPropertyFlag )
   {
      FInfo.Event = Node->GetPropertyUpper("EVENT").c_str();
      FInfo.WaitForFile = Node->GetProperty("WAIT_FOR_FILE").c_str();
      FInfo.WaitForTime = Node->GetProperty("WAIT_FOR_TIME").c_str();
      FInfo.WaitForCommand = Node->GetProperty("WAIT_FOR_COMMAND").c_str();
      FInfo.WaitForOperator = Node->GetProperty("WAIT_FOR_OPERATOR") == "Y";
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetProperty("SPECIAL_DATE").c_str();
      FInfo.CondNot = Node->GetProperty("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetProperty("CONDITION_FILE").c_str();
      FInfo.JobTrigger = Node->GetProperty("JOB_TRIGGER").c_str();
      FInfo.Priority = StrToInt(Node->GetProperty("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetProperty("AUTO_RERUN").c_str();
      FInfo.Tag = Node->GetProperty("TAG").c_str();
   }
   else
   {
      FInfo.Event = Node->GetValueUpper("EVENT").c_str();
      FInfo.WaitForFile = Node->GetValue("WAIT_FOR_FILE").c_str();
      FInfo.WaitForTime = Node->GetValue("WAIT_FOR_TIME").c_str();
      FInfo.WaitForCommand = Node->GetValue("WAIT_FOR_COMMAND").c_str();
      FInfo.WaitForOperator = Node->GetValue("WAIT_FOR_OPERATOR") == "Y";
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetValue("SPECIAL_DATE").c_str();
      FInfo.CondNot = Node->GetValue("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetValue("CONDITION_FILE").c_str();
      FInfo.JobTrigger = Node->GetValue("JOB_TRIGGER").c_str();
      FInfo.Priority = StrToInt(Node->GetValue("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetValue("AUTO_RERUN").c_str();
      FInfo.Tag = Node->GetValue("TAG").c_str();
   }

   if ( FInfo.AutoRerun == "0" )
   {
      FInfo.AutoRerun = "";
   }

   Node->GetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

UTF8String __fastcall HStageEventWait::GetCaption(void)
{
   return "";
}

bool __fastcall HStageEventWait::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageEventWait::GetExternFlag(void)
{
   return !FInfo.ExternJobList.empty();
}

bool __fastcall HStageEventWait::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageEventWait::GetIconType(void)
{
   return 4;
}

void __fastcall HStageEventWait::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapFwBg[0]->Width;
   Height = h_g::BitmapFwBg[0]->Height;
}

UTF8String __fastcall HStageEventWait::GetHint()
{
   UTF8String Hint = h_g::I18nString("h_stage:EVENT_WAIT_HINT");

   if ( FInfo.Event != "" )
   {
      Hint += UTF8String(h_g::I18nString("h_stage:EVENT")) + FInfo.Event;
   }

   if ( FInfo.WaitForFile != "" )
   {
      Hint += UTF8String(h_g::I18nString("h_stage:WAIT_FILE")) + FInfo.WaitForFile;
   }

   if ( FInfo.WaitForTime != "" )
   {
      Hint += UTF8String(h_g::I18nString("h_stage:WAIT_TIME")) + FInfo.WaitForTime;
   }

   if ( FInfo.WaitForCommand != "" )
   {
      Hint += UTF8String(h_g::I18nString("h_stage:WAIT_COMMAND")) + FInfo.WaitForCommand;
   }

   if( FInfo.Description != "" )
   {
      vector<string> Text;
      h_base::SplitString(FInfo.Description.c_str(), '\n', Text);
      for( int i = 0; i < Text.size(); i++ )
      {
         if( i == 0 )
            Hint += UTF8String(h_g::I18nString("h_stage:DESCRIPTION")) +
               Text[i].c_str();
         else
            Hint += UTF8String("\n              ") + Text[i].c_str();
      }
   }

   return Hint;
}

void __fastcall HStageEventWait::GetJobListInfo(const UTF8String &GroupId,
   HJobListInfo &JobListInfo)
{
   JobListInfo = HJobListInfo();
   JobListInfo.Name = GroupId + h_g::JobNameDelimiter + GetName();
   JobListInfo.Command = UTF8String("simbat_evnt wait \"") +
      FInfo.Event + "\" \"" +
      FInfo.WaitForFile + "\" \"" +
      FInfo.WaitForTime + "\" '" +
      FInfo.WaitForCommand + "'";
   JobListInfo.CommandUpper = JobListInfo.Command.UpperCase();
   JobListInfo.TagUpper = FInfo.Tag.UpperCase();
}

void __fastcall HStageEventWait::GetInfo(HInfo &Info)
{
   FInfo.Name = GetName();
   Info = FInfo;
}

bool __fastcall HStageEventWait::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   if( Info.Name != FInfo.Name )
   {
      if( MainForm->ControlExist(Info.Name) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:DUPLICATED_NAME")) +
            Info.Name + ")";
         return false;
      }
      if( !IsValidJobName(Info.Name.c_str()) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_NAME")) +
            Info.Name + ")";
         return false;
      }
   }

   if( Info.Event == "" && Info.WaitForFile == "" &&
       Info.WaitForTime == "" && Info.WaitForCommand == "" )
   {
      ErrorString = h_g::I18nString("h_stage:WAIT_FOR_WHAT");
      return false;
   }

   FInfo = Info;
   SetName(Info.Name);
   RefreshCaption();
   return true;
}

// class HStageGroup

HStage * __fastcall HStageGroup::Clone(void)
{
   return new HStageGroup;
}

UTF8String __fastcall HStageGroup::GetType(void)
{
   return "GROUP";
}

int __fastcall HStageGroup::GetIconEnlarge(void)
{
   return FInfo.Enlarge;
}

bool __fastcall HStageGroup::EditProperty(void)
{
   return GroupForm->Edit(this);
}

void __fastcall HStageGroup::SaveProperty(HXmlTree *Node)
{
   char TmpStr[80 + 1];

   Node->SetProperty("GROUP", FInfo.Group.c_str());
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   Node->SetProperty("SPECIAL_DATE", FInfo.SpecialDate.c_str());
   Node->SetProperty("BUSINESS_TYPE", FInfo.BusinessType.c_str());
   Node->SetProperty("COND_NOT", FInfo.CondNot ? "Y" : "");
   Node->SetProperty("CONDITION_FILE", FInfo.ConditionFile.c_str());
   snprintf(TmpStr, 80, "%d", FInfo.ParallelJobNumber);
   Node->SetProperty("PARALLEL_JOB_NUMBER", TmpStr, "0");
   snprintf(TmpStr, 80, "%d", FInfo.Priority);
   Node->SetProperty("PRIORITY", TmpStr, "0");
   Node->SetProperty("AUTO_RERUN", FInfo.AutoRerun.c_str());
   snprintf(TmpStr, 80, "%d", FInfo.Enlarge);
   Node->SetProperty("ENLARGE", TmpStr, "0");
   Node->SetProperty("TAG", FInfo.Tag.c_str());
   Node->SetProperty("RUNNING_GROUP", FInfo.RunningGroup.c_str());
   Node->SetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

void __fastcall HStageGroup::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   if ( XmlPropertyFlag )
   {
      FInfo.Group = Node->GetPropertyUpper("GROUP").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetProperty("SPECIAL_DATE").c_str();
      FInfo.BusinessType = Node->GetProperty("BUSINESS_TYPE").c_str();
      FInfo.CondNot = Node->GetProperty("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetProperty("CONDITION_FILE").c_str();
      FInfo.ParallelJobNumber = StrToInt(Node->GetProperty("PARALLEL_JOB_NUMBER").c_str());
      FInfo.Priority = StrToInt(Node->GetProperty("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetProperty("AUTO_RERUN").c_str();
      FInfo.Enlarge = StrToInt(Node->GetProperty("ENLARGE").c_str());
      FInfo.Tag = Node->GetProperty("TAG").c_str();
      FInfo.RunningGroup = Node->GetProperty("RUNNING_GROUP").c_str();
   }
   else
   {
      FInfo.Group = Node->GetValueUpper("GROUP").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetValue("SPECIAL_DATE").c_str();
      FInfo.BusinessType = Node->GetValue("BUSINESS_TYPE").c_str();
      FInfo.CondNot = Node->GetValue("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetValue("CONDITION_FILE").c_str();
      FInfo.ParallelJobNumber = StrToInt(Node->GetValue("PARALLEL_JOB_NUMBER").c_str());
      FInfo.Priority = StrToInt(Node->GetValue("PRIORITY").c_str());
      FInfo.AutoRerun = Node->GetValue("AUTO_RERUN").c_str();
      FInfo.Enlarge = StrToInt(Node->GetValue("ENLARGE").c_str());
      FInfo.Tag = Node->GetValue("TAG").c_str();
      FInfo.RunningGroup = Node->GetValue("RUNNING_GROUP").c_str();
   }

   if ( FInfo.AutoRerun == "0" )
   {
      FInfo.AutoRerun = "";
   }

   Node->GetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

UTF8String __fastcall HStageGroup::GetCaption(void)
{
   return FInfo.Group;
}

bool __fastcall HStageGroup::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageGroup::GetExternFlag(void)
{
   return !FInfo.ExternJobList.empty();
}

bool __fastcall HStageGroup::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageGroup::GetIconType(void)
{
   return 5;
}

void __fastcall HStageGroup::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapGroupBg1[0]->Width * ( FInfo.Enlarge + 3 );
   Height = h_g::BitmapGroupBg1[0]->Height;
}

UTF8String __fastcall HStageGroup::GetHint()
{
   char TmpStr[8192 + 1];
   snprintf(TmpStr, 8192, h_g::I18nString("h_stage:GROUP_HINT"), FInfo.Group.c_str());
   UTF8String Hint = TmpStr;

   if( FInfo.Description != "" )
   {
      vector<string> Text;
      h_base::SplitString(FInfo.Description.c_str(), '\n', Text);
      for( int i = 0; i < Text.size(); i++ )
      {
         if( i == 0 )
            Hint += UTF8String(h_g::I18nString("h_stage:DESCRIPTION")) +
               Text[i].c_str();
         else
            Hint += UTF8String("\n              ") + Text[i].c_str();
      }
   }

   return Hint;
}

void __fastcall HStageGroup::GetJobListInfo(const UTF8String &GroupId,
   HJobListInfo &JobListInfo)
{
   JobListInfo = HJobListInfo();
   JobListInfo.Name = GroupId + h_g::JobNameDelimiter + GetName();
   JobListInfo.Command = UTF8String("Group = ") + FInfo.Group;
   JobListInfo.CommandUpper = JobListInfo.Command.UpperCase();
   JobListInfo.TagUpper = FInfo.Tag.UpperCase();
}

void __fastcall HStageGroup::GetInfo(HInfo &Info)
{
   FInfo.Name = GetName();
   Info = FInfo;
}

bool __fastcall HStageGroup::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   if( Info.Name != FInfo.Name )
   {
      if( MainForm->ControlExist(Info.Name) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:DUPLICATED_NAME")) +
            Info.Name + ")";
         return false;
      }
      if( !IsValidJobName(Info.Name.c_str()) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_NAME")) +
            Info.Name + ")";
         return false;
      }
   }

   if( Info.Group == "" )
   {
      ErrorString = h_g::I18nString("h_stage:GROUP_MUST_NOT_BE_EMPTY");
      return false;
   }

   FInfo = Info;
   SetName(Info.Name);
   RefreshCaption();
   return true;
}

// class HStageTime

HStage * __fastcall HStageTime::Clone(void)
{
   return new HStageTime;
}

UTF8String __fastcall HStageTime::GetType(void)
{
   return "TIME";
}

int __fastcall HStageTime::GetIconEnlarge(void)
{
   return 0;
}

bool __fastcall HStageTime::EditProperty(void)
{
   return TimeForm->Edit(this);
}

void __fastcall HStageTime::SaveProperty(HXmlTree *Node)
{
   Node->SetProperty("TIME", FInfo.Time.c_str());
   Node->SetValues("DESCRIPTION", FInfo.Description.c_str());
   Node->SetProperty("SPECIAL_DATE", FInfo.SpecialDate.c_str());
   Node->SetProperty("COND_NOT", FInfo.CondNot ? "Y" : "");
   Node->SetProperty("CONDITION_FILE", FInfo.ConditionFile.c_str());
   Node->SetProperty("TAG", FInfo.Tag.c_str());
   Node->SetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

void __fastcall HStageTime::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
   if ( XmlPropertyFlag )
   {
      FInfo.Time = Node->GetProperty("TIME").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetProperty("SPECIAL_DATE").c_str();
      FInfo.CondNot = Node->GetProperty("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetProperty("CONDITION_FILE").c_str();
      FInfo.Tag = Node->GetProperty("TAG").c_str();
   }
   else
   {
      FInfo.Time = Node->GetValue("TIME").c_str();
      FInfo.Description = Node->GetValues("DESCRIPTION").c_str();
      FInfo.SpecialDate = Node->GetValue("SPECIAL_DATE").c_str();
      FInfo.CondNot = Node->GetValue("COND_NOT") == "Y";
      FInfo.ConditionFile = Node->GetValue("CONDITION_FILE").c_str();
      FInfo.Tag = Node->GetValue("TAG").c_str();
   }

   Node->GetValues("EXTERN_JOB_LIST", FInfo.ExternJobList);
}

UTF8String __fastcall HStageTime::GetCaption(void)
{
   return FInfo.Time;
}

bool __fastcall HStageTime::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageTime::GetExternFlag(void)
{
   return !FInfo.ExternJobList.empty();
}

bool __fastcall HStageTime::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageTime::GetIconType(void)
{
   return 6;
}

void __fastcall HStageTime::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapTimeBg[0]->Width;
   Height = h_g::BitmapTimeBg[0]->Height;
}

UTF8String __fastcall HStageTime::GetHint()
{
   return "";
}

void __fastcall HStageTime::GetJobListInfo(const UTF8String &GroupId,
   HJobListInfo &JobListInfo)
{
   JobListInfo = HJobListInfo();
   JobListInfo.Name = GroupId + h_g::JobNameDelimiter + GetName();
   JobListInfo.Command = UTF8String("simbat_evnt wait '' '' '") +
      FInfo.Time + "' ''";
   JobListInfo.CommandUpper = JobListInfo.Command.UpperCase();
   JobListInfo.TagUpper = FInfo.Tag.UpperCase();
}

void __fastcall HStageTime::GetInfo(HInfo &Info)
{
   FInfo.Name = GetName();
   Info = FInfo;
}

bool __fastcall HStageTime::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   if( Info.Name != FInfo.Name )
   {
      if( MainForm->ControlExist(Info.Name) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:DUPLICATED_NAME")) +
            Info.Name + ")";
         return false;
      }
      if( !IsValidJobName(Info.Name.c_str()) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_NAME")) +
            Info.Name + ")";
         return false;
      }
   }

   {
      const char *s = Info.Time.c_str();
      if ( !isdigit(s[0]) || !isdigit(s[1]) ||
           s[2] != ':' || !isdigit(s[3]) || !isdigit(s[4]) || s[5] != '\0' )
      {
         ErrorString = h_g::I18nString("h_stage:INCORRECT_TIME_FORMAT");
         return false;
      }
      int Hour = ( s[0] - '0' ) * 10 + ( s[1] - '0' );
      int Min = ( s[3] - '0' ) * 10 + ( s[4] - '0' );
      if ( Hour > 23 || Min > 59 )
      {
         ErrorString = h_g::I18nString("h_stage:INCORRECT_TIME_FORMAT");
         return false;
      }
   }

   FInfo = Info;
   SetName(Info.Name);
   RefreshCaption();
   return true;
}

// class HStageBatch

HStage * __fastcall HStageBatch::Clone(void)
{
   return new HStageBatch;
}

UTF8String __fastcall HStageBatch::GetType(void)
{
   return "BATCH";
}

int __fastcall HStageBatch::GetIconEnlarge(void)
{
   return FInfo.Enlarge;
}

bool __fastcall HStageBatch::EditProperty(void)
{
#ifdef SIMBAT_ENTERPRISE
   return BatchJobForm->Edit(this);
#else
   ShowMessage(UTF8String(h_g::I18nString("h_g:ENTERPRISE_ONLY")));
   return false;
#endif
}

void __fastcall HStageBatch::SaveProperty(HXmlTree *Node)
{
#ifdef SIMBAT_ENTERPRISE
   SaveProperty_aux(Node);
#endif
}

void __fastcall HStageBatch::LoadProperty(HXmlTree *Node, bool XmlPropertyFlag)
{
#ifdef SIMBAT_ENTERPRISE
   LoadProperty_aux(Node, XmlPropertyFlag);
#endif
}

UTF8String __fastcall HStageBatch::GetCaption(void)
{
   return FInfo.Caption;
}

bool __fastcall HStageBatch::GetPartFlag(void)
{
   return false;
}

bool __fastcall HStageBatch::GetExternFlag(void)
{
   return !FInfo.ExternJobList.empty();
}

bool __fastcall HStageBatch::GetLoopFlag(void)
{
   return false;
}

int __fastcall HStageBatch::GetIconType(void)
{
   return 7;
}

void __fastcall HStageBatch::GetIconSize(int &Width, int &Height)
{
   Width = h_g::BitmapBatchBg1[0]->Width * ( FInfo.Enlarge + 3 );
   Height = h_g::BitmapBatchBg1[0]->Height;
}

UTF8String __fastcall HStageBatch::GetHint()
{
   char TmpStr[8192 + 1];

   snprintf(TmpStr, 8192, h_g::I18nString("h_stage:BATCH_HINT"),
      GetName().c_str(), FInfo.HostName.c_str(), FInfo.Batch.c_str(), FInfo.Tag.c_str());
   UTF8String Hint = TmpStr;

   if( FInfo.Description != "" )
   {
      vector<string> Text;
      h_base::SplitString(FInfo.Description.c_str(), '\n', Text);
      for( int i = 0; i < Text.size(); i++ )
      {
         if( i == 0 )
            Hint += UTF8String(h_g::I18nString("h_stage:DESCRIPTION")) + Text[i].c_str();
         else
            Hint += UTF8String("\n              ") + Text[i].c_str();
      }
   }

   return Hint;
}

void __fastcall HStageBatch::GetJobListInfo(const UTF8String &GroupId,
   HJobListInfo &JobListInfo)
{
   JobListInfo = HJobListInfo();
   JobListInfo.Name = GroupId + h_g::JobNameDelimiter + GetName();
   JobListInfo.Command = UTF8String("Caption = ") + FInfo.Caption;
   JobListInfo.CommandUpper = JobListInfo.Command.UpperCase();
   JobListInfo.TagUpper = FInfo.Tag.UpperCase();
}

void __fastcall HStageBatch::GetInfo(HInfo &Info)
{
   FInfo.Name = GetName();
   Info = FInfo;
}

bool __fastcall HStageBatch::SetInfo(const HInfo &Info,
   UTF8String &ErrorString)
{
   if( Info.Name != FInfo.Name )
   {
      if( MainForm->ControlExist(Info.Name) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:DUPLICATED_NAME")) +
            Info.Name + ")";
         return false;
      }
      if( !IsValidJobName(Info.Name.c_str()) )
      {
         ErrorString = UTF8String(h_g::I18nString("h_stage:INVALID_NAME")) +
            Info.Name + ")";
         return false;
      }
   }

   if( Info.Caption == "" )
   {
      ErrorString = h_g::I18nString("h_stage:CAPTION_MUST_NOT_BE_EMPTY");
      return false;
   }

   if( Info.HostName == "" )
   {
      ErrorString = h_g::I18nString("h_stage:HOST_NAME_MUST_NOT_BE_EMPTY");
      return false;
   }

   if( Info.Batch == "" )
   {
      ErrorString = h_g::I18nString("h_stage:BATCH_MUST_NOT_BE_EMPTY");
      return false;
   }

   FInfo = Info;
   SetName(Info.Name);
   RefreshCaption();
   return true;
}

#pragma package(smart_init)
